import 'dart:math';

import 'package:flutter/material.dart';
import 'package:pp_uikit/date_picker/pp_base_picker.dart';
import 'package:pp_uikit/date_picker/pp_date_time_formatter.dart';
import 'package:pp_uikit/date_picker/pp_picker_header.dart';
import 'package:pp_uikit/theme/pp_default_theme.dart';
import 'package:pp_uikit/theme/pp_picker_theme.dart';

enum ColumnType { year, month, day }

/// 有31天的月份
const List<int> _solarMonthsOf31Days = <int>[1, 3, 5, 7, 8, 10, 12];

// ignore: must_be_immutable
class PPDateWidget extends StatefulWidget {
  final DateTime? minDateTime, maxDateTime, initDateTime;
  final String? dateFormat;
  final DateVoidCallback? onCancel;
  final DateValueCallback? onChange, onConfirm;
  final bool canPop;
  final double? pickerHeight;
  final bool showHeader;

  /// 未选中的样式
  final TextStyle itemTextStyle;

  /// 选中的样式
  TextStyle? itemTextSelectedStyle;

  /// 主题色
  Color? themeColor;

  PPDateWidget({
    Key? key,
    this.minDateTime,
    this.maxDateTime,
    this.initDateTime,
    this.dateFormat = datetimePickerDateDefaultFormat,
    this.pickerHeight,
    this.showHeader = true,
    this.itemTextStyle =
        const TextStyle(color: Color(0xFF999999), fontSize: 20),
    this.itemTextSelectedStyle,
    this.onCancel,
    this.onChange,
    this.onConfirm,
    this.canPop = true,
    this.themeColor,
  }) : super(key: key) {
    itemTextSelectedStyle ??= TextStyle(
        color: themeColor ?? PPDefaultTheme.instance.brandPrimary,
        fontWeight: FontWeight.w500,
        fontSize: 20);
  }

  @override
  State<StatefulWidget> createState() =>
      // ignore: no_logic_in_create_state
      _PPDateWidgetState(minDateTime, maxDateTime, initDateTime);
}

class _PPDateWidgetState extends State<PPDateWidget> {
  late DateTime _minDateTime, _maxDateTime;
  late int _currYear, _currMonth, _currDay;
  late List<int> _yearRange, _monthRange, _dayRange;
  late FixedExtentScrollController? _yearScrollCtrl,
      _monthScrollCtrl,
      _dayScrollCtrl;
  late Map<String, FixedExtentScrollController?> _scrollCtrlMap;
  late Map<String, List<int>?> _valueRangeMap;
  bool _isChangeDateRange = false;
  _PPDateWidgetState(
      DateTime? minDateTime, DateTime? maxDateTime, DateTime? initialDateTime) {
    // 当前选中的（年、月、日）
    DateTime initDateTime = initialDateTime ?? DateTime.now();
    _currYear = initDateTime.year;
    _currMonth = initDateTime.month;
    _currDay = initDateTime.day;

    // 时间范围
    _minDateTime = minDateTime ?? DateTime.parse(datePickerMinDatetime);
    _maxDateTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime);

    // 可选年份
    _yearRange = _calcYearRange();
    _currYear = min(max(_minDateTime.year, _currYear), _maxDateTime.year);

    // 可选月份
    _monthRange = _calcMonthRange();
    _currMonth = min(max(_monthRange.first, _currMonth), _monthRange.last);

    // 可选天数
    _dayRange = _calcDayRange();
    _currDay = min(max(_dayRange.first, _currDay), _dayRange.last);

    // 创建controller
    _yearScrollCtrl =
        FixedExtentScrollController(initialItem: _currYear - _yearRange.first);
    _monthScrollCtrl = FixedExtentScrollController(
        initialItem: _currMonth - _monthRange.first);
    _dayScrollCtrl =
        FixedExtentScrollController(initialItem: _currDay - _dayRange.first);

    _scrollCtrlMap = {
      'y': _yearScrollCtrl,
      'M': _monthScrollCtrl,
      'd': _dayScrollCtrl
    };
    _valueRangeMap = {'y': _yearRange, 'M': _monthRange, 'd': _dayRange};
  }
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Material(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                // header
                Visibility(
                  visible: widget.showHeader,
                  child: PPPickerHeader(
                    confirmTextStyle: PPPickerTheme.confirmTextStyle.merge(
                        TextStyle(color: widget.itemTextSelectedStyle?.color)),
                    onCancel: () => _onPressedCancel(),
                    onConfirm: () => _onPressedConfirm(),
                  ),
                ),

                // picker
                _buildDatePickerWidget(),
              ],
            )
          ],
        ),
      ),
    );
  }

  /// 创建Picker
  Widget _buildDatePickerWidget() {
    // List<Widget> pickers = [];
    List<String> formats = [];
    if (widget.dateFormat != null) {
      formats = PPDateTimeFormatter.splitDateFormat(widget.dateFormat);
    }

    return Row(
      children: [
        for (var element in formats)
          _buildDatePickerColumn(
            scrollController: _findScrollController(element),
            valueRange: _findPickerItemRange(element)!,
            format: element,
            valueChanged: (value) {
              if (element.contains('y')) {
                _changeYearSelection(value);
              } else if (element.contains('M')) {
                _changeMonthSelection(value);
              } else if (element.contains('d')) {
                _changeDaySelection(value);
              }
            },
          )
      ],
    );
  }

  /// 创建（年、月、日）滚动控件
  Widget _buildDatePickerColumn({
    required FixedExtentScrollController? scrollController,
    required List<int> valueRange,
    required String format,
    required ValueChanged<int> valueChanged,
  }) {
    return Expanded(
      flex: 1,
      child: SizedBox(
        height: widget.pickerHeight ?? PPPickerTheme.pickerHeight,
        child: PPBasePicker.build(
          itemExtent: PPPickerTheme.itemHeight,
          scrollController: scrollController,
          onSelectedItemChanged: valueChanged,
          childCount: valueRange.last - valueRange.first + 1,
          itemBuilder: (BuildContext context, int index) {
            return _buildDatePickerItemComponent(
              format.contains("y")
                  ? ColumnType.year
                  : (format.contains("M") ? ColumnType.month : ColumnType.day),
              index,
              valueRange.first + index,
              format,
            );
          },
        ),
      ),
    );
  }

  /// item widget
  Widget _buildDatePickerItemComponent(
      ColumnType columnType, int index, int value, String format) {
    // 未选中
    TextStyle textStyle = widget.itemTextStyle;

    if ((ColumnType.year == columnType &&
            index == _currentSelectIndexList()[0]) ||
        (ColumnType.month == columnType &&
            index == _currentSelectIndexList()[1]) ||
        (ColumnType.day == columnType &&
            index == _currentSelectIndexList()[2])) {
      // 选中
      if (widget.itemTextSelectedStyle != null) {
        textStyle = widget.itemTextSelectedStyle!;
      }
    }
    return Container(
      height: PPPickerTheme.itemHeight,
      alignment: Alignment.center,
      child: Text(
        PPDateTimeFormatter.formatDateTime(value, format),
        style: textStyle,
      ),
    );
  }

  /// 点击取消按钮事件
  void _onPressedCancel() {
    if (widget.onCancel != null) {
      widget.onCancel!();
    }
    if (widget.canPop) Navigator.pop(context);
  }

  /// 点击确认按钮事件
  void _onPressedConfirm() {
    if (widget.onConfirm != null) {
      DateTime dateTime = DateTime(_currYear, _currMonth, _currDay);
      widget.onConfirm!(dateTime, _currentSelectIndexList());
    }
    if (widget.canPop) Navigator.pop(context);
  }

  /// 日期值改变时的回调
  void _onSelectedChange() {
    if (widget.onChange != null) {
      DateTime dateTime = DateTime(_currYear, _currMonth, _currDay);
      widget.onChange!(dateTime, _currentSelectIndexList());
    }
  }

  ///  找到对应的（年、月、日）controller
  FixedExtentScrollController? _findScrollController(String format) {
    FixedExtentScrollController? scrollController;
    _scrollCtrlMap.forEach((key, value) {
      if (format.contains(key)) {
        scrollController = value;
      }
    });
    return scrollController;
  }

  /// 当前选中的（年、月、日）index数组
  List<int> _currentSelectIndexList() {
    int yearIndex = _currYear - _minDateTime.year;
    int monthIndex = _currMonth - _monthRange.first;
    int dayIndex = _currDay - _dayRange.first;
    return [yearIndex, monthIndex, dayIndex];
  }

  /// 改变年
  void _changeYearSelection(int index) {
    int year = _yearRange.first + index;
    if (_currYear != year) {
      _currYear = year;
      _changeDateRange();
      _onSelectedChange();
    }
  }

  /// 改变月
  void _changeMonthSelection(int index) {
    int month = _monthRange.first + index;
    if (_currMonth != month) {
      _currMonth = month;
      _changeDateRange();
      _onSelectedChange();
    }
  }

  /// 改变日
  void _changeDaySelection(int index) {
    int dayOfMonth = _dayRange.first + index;
    if (_currDay != dayOfMonth) {
      _currDay = dayOfMonth;
      _changeDateRange();
      _onSelectedChange();
    }
  }

  /// 改变（月、日）的选择范围
  void _changeDateRange() {
    if (_isChangeDateRange) {
      return;
    }
    _isChangeDateRange = true;

    List<int> monthRange = _calcMonthRange();
    bool monthRangeChanged = _monthRange.first != monthRange.first ||
        _monthRange.last != monthRange.last;
    if (monthRangeChanged) {
      // selected year changed
      _currMonth = max(min(_currMonth, monthRange.last), monthRange.first);
    }

    List<int> dayRange = _calcDayRange();
    bool dayRangeChanged =
        _dayRange.first != dayRange.first || _dayRange.last != dayRange.last;
    if (dayRangeChanged) {
      // day range changed, need limit the value of selected day
      _currDay = max(min(_currDay, dayRange.last), dayRange.first);
    }

    setState(() {
      _monthRange = monthRange;
      _dayRange = dayRange;

      _valueRangeMap['M'] = monthRange;
      _valueRangeMap['d'] = dayRange;
    });

    if (monthRangeChanged) {
      // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999)
      int currMonth = _currMonth;
      _monthScrollCtrl!.jumpToItem(monthRange.last - monthRange.first);
      if (currMonth < monthRange.last) {
        _monthScrollCtrl!.jumpToItem(currMonth - monthRange.first);
      }
    }

    if (dayRangeChanged) {
      // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999)
      int currDay = _currDay;
      _dayScrollCtrl!.jumpToItem(dayRange.last - dayRange.first);
      if (currDay < dayRange.last) {
        _dayScrollCtrl!.jumpToItem(currDay - dayRange.first);
      }
    }

    _isChangeDateRange = false;
  }

  /// 找到对应item的值范围
  List<int>? _findPickerItemRange(String format) {
    List<int>? valueRange;
    _valueRangeMap.forEach((key, value) {
      if (format.contains(key)) {
        valueRange = value;
      }
    });
    return valueRange;
  }

  /// 年的值范围
  List<int> _calcYearRange() {
    return [_minDateTime.year, _maxDateTime.year];
  }

  /// 月的值范围
  List<int> _calcMonthRange() {
    int minMonth = 1, maxMonth = 12;
    int minYear = _minDateTime.year;
    int maxYear = _maxDateTime.year;
    if (minYear == _currYear) {
      // selected minimum year, limit month range
      minMonth = _minDateTime.month;
    }
    if (maxYear == _currYear) {
      // selected maximum year, limit month range
      maxMonth = _maxDateTime.month;
    }
    return [minMonth, maxMonth];
  }

  /// 日的值范围
  List<int> _calcDayRange({currMonth}) {
    int minDay = 1, maxDay = _calcDayCountOfMonth();
    int minYear = _minDateTime.year;
    int maxYear = _maxDateTime.year;
    int minMonth = _minDateTime.month;
    int maxMonth = _maxDateTime.month;
    currMonth ??= _currMonth;
    if (minYear == _currYear && minMonth == currMonth) {
      // selected minimum year and month, limit day range
      minDay = _minDateTime.day;
    }
    if (maxYear == _currYear && maxMonth == currMonth) {
      // selected maximum year and month, limit day range
      maxDay = _maxDateTime.day;
    }
    return [minDay, maxDay];
  }

  /// 当前月有多少天
  int _calcDayCountOfMonth() {
    if (_currMonth == 2) {
      return isLeapYear(_currYear) ? 29 : 28;
    } else if (_solarMonthsOf31Days.contains(_currMonth)) {
      return 31;
    }
    return 30;
  }

  /// 是不是润年
  bool isLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
  }
}
